package com.globant.google.mendoza.malbec;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.thoughtworks.selenium.DefaultSelenium;

/**
 * Visitor implementation using selenium.
 */
public class SeleniumBuyerVisitor implements BuyerVisitor {

  /**
   * The class logger.
   */
  private static Log log = LogFactory.getLog(SeleniumBuyerVisitor.class);

  /**
   * Selenium remote control.
   */
  private DefaultSelenium seleniumRC;

  /**
   * Creates the selenium visitor and stores the selenium remote control.
   * @param theSeleniumRC The remote control used to interact with the ui.
   */
  public SeleniumBuyerVisitor(final DefaultSelenium theSeleniumRC) {
    seleniumRC = theSeleniumRC;
  }

  /**
   * Select an address from the available buyer addresses.
   * @param address the buyer address to select.
   */
  public final void enterAddress(final BuyerAddress address) {
    log.trace("Entering enterAddress");

    String shipToChangeAnchorXPath = getShipToChangeAnchorXPath();

    waitForChangeAnchor();

    seleniumRC.click("xpath=" + shipToChangeAnchorXPath);

    String addressSelectName = "addressBookViewSelect";

    if (!seleniumRC.isElementPresent("name=" + addressSelectName)) {
      throw new RuntimeException(
          "the ship to address select could not be found");
    }

    seleniumRC.select("name=" + addressSelectName, "value="
        + address.getAddressId());

    try {
      Thread.sleep(3500);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    log.trace("Leaving enterAddress");
  }

  /**
   * Create a new address for the buyer and select it.
   * @param address the new address to be created and selected.
   */
  public final void enterNewAddress(final BuyerNewAddress address) {
    log.trace("Entering enterNewAddress");

    String shipToChangeAnchorXPath = getShipToChangeAnchorXPath();

    waitForChangeAnchor();

    seleniumRC.click("xpath=" + shipToChangeAnchorXPath);

    String addressSelectName = "addressBookViewSelect";

    if (!seleniumRC.isElementPresent("name=" + addressSelectName)) {
      throw new RuntimeException(
          "the ship to address select could not be found");
    }

    seleniumRC.select("name=" + addressSelectName,
        "label=Choose a different address.");

    try {
      Thread.sleep(3500);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    //Now the new address could be added.
    seleniumRC.type("address_name", address.getName());
    seleniumRC.type("address_street1", address.getAddress().getAddress1());
    seleniumRC.type("address_street2", address.getAddress().getAddress2());
    seleniumRC.type("address_town", address.getAddress().getCity());
    seleniumRC.type("address_zip", address.getAddress().getZipCode());
    seleniumRC.select("address_state_menu", "value="
        + address.getAddress().getState());
    seleniumRC.type("address.phone", address.getPhone());
    seleniumRC.click("saveaddress");
    log.trace("Leaving enterAddress");
  }

  /**
   * Returns the XPath string for the Change anchor.
   * @return the XPath string.
   */
  private String getShipToChangeAnchorXPath() {
    return "//div[@id='addressView']"
        + "//table//tbody//tr[2]//td[2]//table//tbody//tr[1]//td"
        + "//table//tbody//tr//td[3]//div//a";
  }

  /**
   * Waits for the Change anchor to appear on the page.
   */
  private void waitForChangeAnchor() {

    String shipToChangeAnchorXPath = getShipToChangeAnchorXPath();

    boolean found = false;
    for (int i = 0; i < 30; i++) {
      if (!seleniumRC.isElementPresent("xpath=" + shipToChangeAnchorXPath)) {
        try {
          Thread.sleep(1000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      } else {
        found = true;
        break;
      }
    }
    if (!found) {
      throw new RuntimeException("the Change anchor could not be found using"
          + " xpath=" + shipToChangeAnchorXPath + " in "
          + seleniumRC.getHtmlSource());
    }
  }

  /**
   * Enters a coupon in the place order page and clicks the apply coupon button.
   * @param coupon The coupon that will be entered.
   */
  public final void enterCoupon(final BuyerCoupon coupon) {
    log.trace("Entering enterCoupon");

    seleniumRC.type("id=couponEntryField", coupon.getCouponCode());
    seleniumRC.click("id=applyCoupon");

    log.trace("Leaving enterCoupon");
  }

  /**
   * Enters a gift certificate in the place order page and clicks the apply gift
   * certificate button.
   * @param certificate the {@link BuyerGiftCertificate} to be entered.
   */
  public final void enterGiftCertificate(
      final BuyerGiftCertificate certificate) {
    log.trace("Entering enterGiftCertificate");

    seleniumRC.type("id=giftCardEntryField", certificate
        .getGiftCertificateCode());
    seleniumRC.click("id=applyGiftCard");

    log.trace("Leaving enterGiftCertificate");
  }

  /**
   * Checks the keep my email confidential checkbox.
   */
  public final void checkConfidentialEmail() {
    log.trace("Entering checkConfidentialEmail");
    seleniumRC.check("id=useanon");
    log.trace("Leaving checkConfidentialEmail");
  }

  /**
   * Unchecks the keep my email confidential checkbox.
   */
  public final void uncheckConfidentialEmail() {
    log.trace("Entering uncheckConfidentialEmail");
    seleniumRC.uncheck("id=useanon");
    log.trace("Leaving uncheckConfidentialEmail");
  }

  /**
   * Checks the send me promotion emails checkbox.
   */
  public final void checkMarketingEmail() {
    log.trace("Entering checkMarketingEmail");
    seleniumRC.check("id=acceptMarketingEmail");
    log.trace("Leaving checkMarketingEmail");
  }

  /**
   * Unchecks the send me promotion emails checkbox.
   */
  public final void uncheckMarketingEmail() {
    log.trace("Entering uncheckMarketingEmail");
    seleniumRC.uncheck("id=acceptMarketingEmail");
    log.trace("Leaving uncheckMarketingEmail");
  }

  /**
   * Enters a gift message either adding a new one or replacing the existent.
   * @param message the {@link BuyerGiftMessage} to be entered.
   */
  public final void enterGiftMessage(final BuyerGiftMessage message) {
    log.trace("Entering enterGiftMessage");

    /**
     * Edit anchor id.
     */
    String EDIT_ANCHOR_ID = "GOS_EditMessageControlID";

    /**
     * Add anchor id.
     */
    String ADD_ANCHOR_ID = "GOS_AddMessageControlID";

    /**
     * Text area xpath.
     */
    String TEXT_AREA_XPATH = "xpath=//html//body//div[4]//table//tbody//tr[2]"
      + "//td//table//tbody//tr//td[2]//table//tbody//tr[1]//td//textarea";

    /**
     * Apply message button xpath.
     */
    String APPLY_MESSAGE_BUTTON_XPATH =
      "xpath=//button[text()=\"Apply gift message\"]";

    String locator = SeleniumUtil.waitForElementsPresent(
        seleniumRC, new String[] {
            "id=" + ADD_ANCHOR_ID, "id=" + EDIT_ANCHOR_ID }, 3000);
    if (!locator.equals("")) {
      try {
        seleniumRC.click(locator);
        Thread.sleep(1000);

        seleniumRC.type(TEXT_AREA_XPATH, message.getGiftMessage());
        Thread.sleep(10000);

        seleniumRC.click(APPLY_MESSAGE_BUTTON_XPATH);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    } else {
      throw new RuntimeException(
          "The edit anchor for entering a gift message was not found");
    }

    log.trace("Leaving enterGiftMessage");
  }

}
